﻿using JESAI.Application.Abstractions.Dtos;
using JESAI.Application.Abstractions.Sys;
using JESAI.Application.Abstractions.Sys.Dtos;
using JESAI.Application.Abstractions.Sys.Querys;
using JESAI.AutoMapper.ObjectMapping;
using JESAI.Core;
using JESAI.Core.Attributes;
using JESAI.Core.Exceptions;
using JESAI.Core.Extensions;
using JESAI.Core.Util.Extensions.Strings;
using JESAI.Core.Util.Helpers;
using JESAI.DDD.Dtos;
using JESAI.Platform.Domain.Sys.Entities;
using JESAI.Platform.Domain.Sys.Repositories;
using JESAI.Uow;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace JESAI.Application.Service.Sys
{
    [AppService]
    public class OnlineService : IOnlineService
    {
        private readonly IOnlineInfoRepository _onlineInfoRepository;
        private readonly IOnlineFieldRepository _onlineFieldRepository;
        private readonly IUnitOfWorkManager _unitOfWorkManager;
        private readonly IUser _user;

        public OnlineService(IOnlineInfoRepository onlineInfoRepository, IOnlineFieldRepository onlineFieldRepository, IUnitOfWorkManager unitOfWorkManager, IUser user)
        {
            this._onlineInfoRepository = onlineInfoRepository;
            this._onlineFieldRepository = onlineFieldRepository;
            this._unitOfWorkManager = unitOfWorkManager;
            _user = user;

        }

        public async Task DeleteOnlineInfo(string id)
        {
            using (var uow = _unitOfWorkManager.CreateContext())
            {
                try
                {
                    await _onlineInfoRepository.DeleteByIdAsync(id);
                    await _onlineFieldRepository.DeleteAsync(p => p.OnlineInfoId == id);
                    uow.Commit();
                }
                catch (Exception ex)
                {
                    uow.Rollback();
                    throw ex;
                }
            }
        }

        public async Task DeleteOnlineInfos(string[] ids)
        {
            using (var uow = _unitOfWorkManager.CreateContext())
            {
                try
                {
                    await _onlineInfoRepository.DeleteByIdsAsync(ids);
                    await _onlineFieldRepository.DeleteAsync(p => ids.Contains(p.OnlineInfoId));
                    uow.Commit();
                }
                catch (Exception ex)
                {
                    uow.Rollback();
                    throw ex;
                }
            }
        }

        public async Task<List<OnlineFieldDto>> GetOnlineFieldsByOnlineInfoId(string onlineInfoId)
        {
            return await _onlineFieldRepository.GetListAsync(p => p.OnlineInfoId == onlineInfoId).ContinueWith(t => t.Result.MapTo<List<OnlineFieldDto>>());
        }

        public async Task<PagedDto<OnlineInfoDto>> GetPageList(OnlineInfoPageQuery onlineInfoPageQuery)
        {
            var totalNumber = 0;
            var data = _onlineInfoRepository._DbQueryable
                 .WhereIF(!onlineInfoPageQuery.Name.IsEmpty(), it => it.Name.Contains(onlineInfoPageQuery.Name))
                   .WhereIF(!onlineInfoPageQuery.Code.IsEmpty(), it => it.TableCode.Contains(onlineInfoPageQuery.Code))
                    .ToPageList(onlineInfoPageQuery.PageIndex, onlineInfoPageQuery.PageSize, ref totalNumber);
            return new PagedDto<OnlineInfoDto>(totalNumber, data.MapTo<List<OnlineInfoDto>>());
        }

        public async Task SetOnlineInfo(OnlineInfoInput input)
        {
            using (var uow = _unitOfWorkManager.CreateContext())
            {
                try
                {
                    OnlineInfoEntity onlineInfoEntity = await SaveOrUpdateOnlineFieldInfoAsync(input);
                    await SaveOrUpdateOnlineFieldAsync(onlineInfoEntity, input.OnlineFieldInputs);
                    uow.Commit();
                }
                catch (Exception ex)
                {
                    uow.Rollback();
                    throw ex;
                }
            }
        }

        private async Task<OnlineInfoEntity> SaveOrUpdateOnlineFieldInfoAsync(OnlineInfoInput onlineInfoInput)
        {
            OnlineInfoEntity onlineInfoEntity = null;
            if (onlineInfoInput.Id.IsNullOrWhiteSpace())
            {
                onlineInfoEntity = onlineInfoInput.MapTo<OnlineInfoEntity>();
                onlineInfoEntity.Id = Guid.NewGuid().ToString();
                onlineInfoEntity.CreateTime = DateTime.Now;
                onlineInfoEntity.Cid = _user.Id.ToInt();
                await _onlineInfoRepository.InsertAsync(onlineInfoEntity);
            }
            else
            {
                var model = await _onlineInfoRepository.GetByIdAsync(onlineInfoInput.Id);
                onlineInfoInput.MapTo(model);
                model.Uid = _user.Id.ToInt();
                model.UpdateTime = DateTime.Now;
                onlineInfoEntity = model;
                await _onlineInfoRepository.UpdateAsync(model);
            }
            return onlineInfoEntity;
        }

        private async Task SaveOrUpdateOnlineFieldAsync(OnlineInfoEntity onlineInfoEntity, List<OnlineFieldInput> onlineFieldInputs)
        {
            var onlineFieldEntities = onlineFieldInputs.MapTo<List<OnlineFieldEntity>>();
            var updateOnlineFieldColumns = onlineFieldEntities.Where(it => it.Id.IsNotNullOrEmpty()).ToList();
            var insertOnlineFieldColumns = onlineFieldEntities.Where(it => it.Id.IsNullOrEmptyOrWhiteSpace()).ToList();
            if (updateOnlineFieldColumns.Any())
            {
                var updateColumns = _onlineFieldRepository._DbQueryable.Where(it => updateOnlineFieldColumns.Select(c => c.Id).Contains(it.Id)).ToList();
                updateOnlineFieldColumns.ForEach(it =>
                {
                    var column = updateColumns.FirstOrDefault(c => c.Id == it.Id);
                    if (column == null)
                    {
                        return;
                    }
                    it.OnlineInfoId = onlineInfoEntity.Id;
                });
                var updateColumnIds = updateOnlineFieldColumns.Select(p => p.Id).ToArray();
                var delColumnIds = _onlineFieldRepository._DbQueryable.Where(it => !SqlFunc.ContainsArray(updateColumnIds, it.Id)).Select(it => it.Id).ToArray();

                if (delColumnIds.Any())
                {
                    await _onlineFieldRepository.DeleteByIdsAsync(delColumnIds);
                }
                await _onlineFieldRepository.UpdateRangeAsync(updateOnlineFieldColumns);
            }
            if (insertOnlineFieldColumns.Any())
            {
                insertOnlineFieldColumns.ForEach(it =>
                {
                    it.Id = Guid.NewGuid().ToString();
                    it.OnlineInfoId = onlineInfoEntity.Id;
                });
                await _onlineFieldRepository.InsertRangeAsync(insertOnlineFieldColumns);

            }
        }

        public async Task<OnlineInfoDto> GetOnlineInfoByFormCode(string formCode)
        {
            var onlineInfo = await _onlineInfoRepository._DbQueryable.Where(it => it.Code == formCode && it.IsValid).FirstAsync();
            if (onlineInfo == null)
            {
                //throw BuisnessException.NotFound($"找不到{formCode}的表单信息");
                return new OnlineInfoDto();
            }

            var onlineFields = await _onlineFieldRepository.GetListAsync(p => p.OnlineInfoId == onlineInfo.Id && p.IsValid);


            var onlineInfoDto = onlineInfo.MapTo<OnlineInfoDto>();
            onlineInfoDto.Fields = onlineFields.MapTo<List<OnlineFieldDto>>();
            return onlineInfoDto;
        }
    }
}
